package com.sixfoot.server.handler;

import java.util.Calendar;
import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sixfoot.domain.Resource;
import com.sixfoot.domain.User;
import com.sixfoot.domain.scale.Scale;
import com.sixfoot.facade.resource.ResourceDto;
import com.sixfoot.foundation.mapping.BeanMapper;
import com.sixfoot.foundation.persistence.springdata.PagedList;
import com.sixfoot.foundation.rest.ErrorCodeException;
import com.sixfoot.foundation.utils.DateUtils;
import com.sixfoot.foundation.utils.SystemErrorCodes;
import com.sixfoot.hrv.codec.protobuf.ChangePasswordReqProto;
import com.sixfoot.hrv.codec.protobuf.ChangePasswordRespProto;
import com.sixfoot.hrv.codec.protobuf.DataEpReqProto;
import com.sixfoot.hrv.codec.protobuf.DataHrvReqProto;
import com.sixfoot.hrv.codec.protobuf.DataIbiReqProto;
import com.sixfoot.hrv.codec.protobuf.DataPpgReqProto;
import com.sixfoot.hrv.codec.protobuf.GetResourceListReqProto;
import com.sixfoot.hrv.codec.protobuf.LoginReqProto;
import com.sixfoot.hrv.codec.protobuf.LoginRespProto;
import com.sixfoot.hrv.codec.protobuf.RequestProto;
import com.sixfoot.hrv.codec.protobuf.RequestProto.Request;
import com.sixfoot.hrv.codec.protobuf.ResourceListRespProto;
import com.sixfoot.hrv.codec.protobuf.ResourceProto;
import com.sixfoot.hrv.codec.protobuf.ResponseProto;
import com.sixfoot.hrv.codec.protobuf.SaveScaleRespProto;
import com.sixfoot.hrv.codec.protobuf.ScaleListReqProto;
import com.sixfoot.hrv.codec.protobuf.ScaleListRespProto;
import com.sixfoot.hrv.codec.protobuf.ScaleReqProto;
import com.sixfoot.hrv.codec.protobuf.ScaleRespProto;
import com.sixfoot.hrv.codec.protobuf.StartScaleReqProto;
import com.sixfoot.hrv.codec.protobuf.StopScaleReqProto;
import com.sixfoot.hrv.codec.protobuf.UpdateUserInfoReqProto;
import com.sixfoot.hrv.codec.protobuf.UpdateUserInfoRespProto;
import com.sixfoot.hrv.codec.protobuf.UserInfoProto;
import com.sixfoot.service.ResourceService;
import com.sixfoot.service.ScaleService;
import com.sixfoot.service.ServerManager;
import com.sixfoot.service.UserService;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

@Component("reqHandler")
//@Scope("prototype")
@Sharable
public class ReqHandler extends ChannelInboundHandlerAdapter {
	final Logger logger = LoggerFactory.getLogger(ReqHandler.class);
	
	@Autowired
	private UserService userService;
	@Autowired
	private ResourceService resourceService;
	@Autowired
	private ScaleService scaleService;
	
	Scale scale = null;
	
	/* (non-Javadoc)
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 */
	@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
		RequestProto.Request req = (RequestProto.Request) msg;
		
		// 判断请求是哪种类型
		int reqType = req.getType().getNumber();
		if (reqType == Request.Type.LOGIN_VALUE)
			ctx.writeAndFlush(resp(req.getExtension(LoginReqProto.LoginReq.loginReq), ctx));
		
		if (reqType == Request.Type.START_SCALE_VALUE) {
			StartScaleReqProto.StartScaleReq startScaleReq = 
					req.getExtension(StartScaleReqProto.StartScaleReq.startScaleReq);
			if (scale == null) {
				Resource resource = resourceService.getRepository().findOne(startScaleReq.getResource().getId());
				startScaleReq.getDifficulty();
//				scaleTypeService.find(startScaleReq.getType().ordinal());
				scale = new Scale();
				scale.setStartTime(Calendar.getInstance().getTime());
				scale.setResource(resource);
				scale.setDifficulty(startScaleReq.getDifficulty().ordinal());
			}
		}
		if (reqType == Request.Type.STOP_SCALE_VALUE) {
			StopScaleReqProto.StopScaleReq stopScaleReq = 
					req.getExtension(StopScaleReqProto.StopScaleReq.stopScaleReq);
			if (scale != null) {
				scale.setRemark(stopScaleReq.getRemark());
				scale.setEvaluation(stopScaleReq.getEvaluationList().toString());
				scale.setFrequencyDomain(stopScaleReq.getFrequencyDomainList().toString());
				scale.setTimeDomain(stopScaleReq.getTimeDomainList().toString());
				scale.setPpg(stopScaleReq.getSpectrumList().toString());
				scale.setUser((User) SecurityUtils.getSubject().getSession().getAttribute("user"));
				scale.setStopTime(Calendar.getInstance().getTime());
				scaleService.getRepository().save(scale);
				scale = null;
				
				SaveScaleRespProto.SaveScaleResp.Builder saveScaleBuilder = 
						SaveScaleRespProto.SaveScaleResp.newBuilder();
				saveScaleBuilder.setResult("记录存储成功");
				
				ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
				respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.SAVE_SCALE);
				respSuccessBuilder.setExtension(SaveScaleRespProto.SaveScaleResp.saveScaleResp, saveScaleBuilder.build());
				
				ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
				resultBuilder.setStatus(ResponseProto.Response.Status.OK);
				resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
				ctx.writeAndFlush(resultBuilder.build());
			}
		}
		if (reqType == Request.Type.DATA_PPG_VALUE) {
			DataPpgReqProto.DataPpgReq ppg = 
					req.getExtension(DataPpgReqProto.DataPpgReq.dataPpgReq);
			if (scale != null) {
				String ppgStr = scale.getPpg() == null ? "" : scale.getPpg() + ",";
				List<Float> ppgList = ppg.getValueList();
				for (Float f : ppgList) {
					ppgStr += f.toString() + ",";
				}
				scale.setPpg(ppgStr.substring(0, ppgStr.length() - 1));
			}
		}
		if (reqType == Request.Type.RESOURCE_LIST_VALUE) {
			GetResourceListReqProto.GetResourceListReq getResourceListReq = 
				req.getExtension(GetResourceListReqProto.GetResourceListReq.getResourceListReq);
//			resourceService.loadChilds(getResourceListReq.getId());
			ctx.writeAndFlush(getResourceList(getResourceListReq.getId()));
		}
	    if (reqType == Request.Type.MARK_SCALE_VALUE) {
	    	
	    }
		if (reqType == Request.Type.DATA_EP_VALUE) {
			DataEpReqProto.DataEpReq ep = 
					req.getExtension(DataEpReqProto.DataEpReq.dataEpReq);
			if (scale != null) {
				String epStr = scale.getEp() == null ? "" : scale.getEp() + ",";
				String ppgStr = scale.getPpg() == null ? "" : scale.getPpg() + ",";
				List<Float> epList = ep.getValueList();
				List<Float> ppgList = ep.getSpectrumList();
				for (int i = 0; i < epList.size(); i++) {
					epStr += epList.get(i).toString() + ",";
					ppgStr += ppgList.get(i).toString() + ",";
				}
				scale.setEp(epStr.substring(0, epStr.length() - 1));
				scale.setPpg(ppgStr.substring(0, ppgStr.length() - 1));
			}
		}
		if (reqType == Request.Type.DATA_IBI_VALUE) {
			DataIbiReqProto.DataIbiReq ibi = 
					req.getExtension(DataIbiReqProto.DataIbiReq.dataIbiReq);
			if (scale != null) {
				String ibiStr = scale.getIbi() == null ? "" : scale.getIbi() + ",";
				List<Float> ibiList = ibi.getValueList();
				for (Float f : ibiList) {
					ibiStr += f.toString() + ",";
				}
				scale.setIbi(ibiStr.substring(0, ibiStr.length() - 1));
			}
		}
		if (reqType == Request.Type.DATA_HRV_VALUE) {
			DataHrvReqProto.DataHrvReq hrv = 
					req.getExtension(DataHrvReqProto.DataHrvReq.dataHrvReq);
			if (scale != null) {
				String hrvStr = scale.getHrv() == null ? "" : scale.getHrv() + ",";
				String artifactStr = scale.getArtifact() == null ? "" : scale.getArtifact() + ",";
				List<Float> hrvList = hrv.getValueList();
				List<Boolean> artifactList = hrv.getIsArtifactList();
				for (int i = 0; i < hrvList.size(); i++) {
					hrvStr += hrvList.get(i).toString() + ",";
					artifactStr += artifactList.get(i) ? 1 : 0 + ",";
				}
				scale.setHrv(hrvStr.substring(0, hrvStr.length() - 1));
				scale.setArtifact(artifactStr.substring(0, artifactStr.length() - 1));
			}
		}
		if (reqType == Request.Type.GET_SCALE_LIST_VALUE) { 
			ScaleListReqProto.ScaleListReq scaleListReq = 
					req.getExtension(ScaleListReqProto.ScaleListReq.scaleListReq);
			PagedList<Scale> scaleList = 
					scaleService.findByResourceId(scaleListReq.getResource().getId(), scaleListReq.getPageNum() - 1, scaleListReq.getPageSize());
			
			
			ScaleListRespProto.ScaleListResp.Builder scaleListRespBuilder =
					ScaleListRespProto.ScaleListResp.newBuilder();
			scaleListRespBuilder.setResult("获取列表成功");
			scaleListRespBuilder.setTotalCount((int) scaleList.getTotalCount());
			scaleListRespBuilder.setTotalPages((int) scaleList.getTotalPages());
			scaleListRespBuilder.setPage(scaleList.getPage());
			scaleListRespBuilder.setSize(scaleList.getSize());
			for (Scale scale : scaleList.getResult()) {
				ResourceProto.Resource resource = ResourceProto.Resource.newBuilder()
						.setId(scale.getResource().getId())
						.setName(scale.getResource().getName())
						.build();
				com.sixfoot.hrv.codec.protobuf.ScaleProto.Scale scaleProto = 
						com.sixfoot.hrv.codec.protobuf.ScaleProto.Scale.newBuilder()
							.setScaleId(scale.getId())
							.setDifficulty(scale.getDifficulty())
							.setEvaluation(scale.getEvaluation())
							.setResource(resource)
							.setStartTime(scale.getStartTime() == null ? "" : DateUtils.format(scale.getStartTime()))
							.setStopTime(scale.getStopTime() == null ? "" : DateUtils.format(scale.getStopTime()))
							.build();
				scaleListRespBuilder.addScale(scaleProto);
			}
			
			ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
			respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.GET_SCALE_LIST);
			respSuccessBuilder.setExtension(ScaleListRespProto.ScaleListResp.scaleListResp, scaleListRespBuilder.build());
			
			ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
			resultBuilder.setStatus(ResponseProto.Response.Status.OK);
			resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
			ctx.writeAndFlush(resultBuilder.build());
		}
		if (reqType == Request.Type.GET_SCALE_VALUE) { 
			ScaleReqProto.ScaleReq scaleReq = req.getExtension(ScaleReqProto.ScaleReq.scaleReq);
			Scale scale = scaleService.findOne(scaleReq.getScaleId());
			ResourceProto.Resource resource = ResourceProto.Resource.newBuilder()
					.setId(scale.getResource().getId())
					.setName(scale.getResource().getName())
					.build();
			ScaleRespProto.ScaleResp scaleRespProto = ScaleRespProto.ScaleResp.newBuilder()
					.setScaleId(scale.getId())
					.setDifficulty(scale.getDifficulty())
					.setEvaluation(scale.getEvaluation())
					.setResource(resource)
					.setStartTime(scale.getStartTime() == null ? "" : DateUtils.format(scale.getStartTime()))
					.setStopTime(scale.getStopTime() == null ? "" : DateUtils.format(scale.getStopTime()))
					.setPpg(scale.getPpg())
					.setArtifact(scale.getArtifact() == null ? "" : scale.getArtifact())
					.setEp(scale.getEp())
					.setHrv(scale.getHrv() == null ? "" : scale.getHrv())
					.setFrequencyDomain(scale.getFrequencyDomain())
					.setIbi(scale.getIbi())
					.setRemark(scale.getRemark())
					.setResult("获取记录成功")
					.setTimeDomain(scale.getTimeDomain())
					.setSpectrum(scale.getSpectrum() == null ? "" : scale.getSpectrum())
					.build();
			
			ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
			respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.GET_SCALE);
			respSuccessBuilder.setExtension(ScaleRespProto.ScaleResp.scaleResp, scaleRespProto);
			
			ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
			resultBuilder.setStatus(ResponseProto.Response.Status.OK);
			resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
			ctx.writeAndFlush(resultBuilder.build());
		}
		switch (req.getType().getNumber()) {
			case (Request.Type.CHANGE_PASSWORD_VALUE):
				// 判断是否登录
				if (!SecurityUtils.getSubject().isAuthenticated()) {
					ctx.writeAndFlush(error());
				}
				// 判断是否有权限操作
				// 判断旧密码是否匹配
				ChangePasswordReqProto.ChangePasswordReq changePasswordReq = 
					req.getExtension(ChangePasswordReqProto.ChangePasswordReq.changePasswordReq);
				try {
					userService.updatePassword(changePasswordReq.getUsername(), changePasswordReq.getNewPassword());
				} catch (ErrorCodeException e) {
					
				}
				
				ChangePasswordRespProto.ChangePasswordResp.Builder changePasswordBuilder = 
						ChangePasswordRespProto.ChangePasswordResp.newBuilder();
				changePasswordBuilder.setResult("修改密码成功");

				ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
				respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.CHANGE_PASSWORD);
				respSuccessBuilder.setExtension(ChangePasswordRespProto.ChangePasswordResp.changePasswordResp, changePasswordBuilder.build());
				
				ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
				resultBuilder.setStatus(ResponseProto.Response.Status.OK);
				resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
				ctx.writeAndFlush(resultBuilder.build());
				break;
			case (Request.Type.UPDATE_USER_INFO_VALUE):
				// 判断是否登录
				if (!SecurityUtils.getSubject().isAuthenticated()) {
					ctx.writeAndFlush(error());
				}
			
				UpdateUserInfoReqProto.UpdateUserInfoReq updateUserInfoReq =
					req.getExtension(UpdateUserInfoReqProto.UpdateUserInfoReq.updateUserInfoReq);
				try {
					User user = BeanMapper.map(updateUserInfoReq, User.class);
					userService.getRepository().save(user);
				} catch (ErrorCodeException e) {
					System.out.println(e.getErrorCode());
				}
				
				UpdateUserInfoRespProto.UpdateUserInfoResp.Builder updateUserInfoBuilder = 
						UpdateUserInfoRespProto.UpdateUserInfoResp.newBuilder();
				updateUserInfoBuilder.setResult("更新用户信息成功");

				/*ResponseProto.RespSuccess.Builder */respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
				respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.UPDATE_USER_INFO);
				respSuccessBuilder.setExtension(UpdateUserInfoRespProto.UpdateUserInfoResp.updateUserInfoResp, updateUserInfoBuilder.build());
				
				/*ResponseProto.Response.Builder */resultBuilder = ResponseProto.Response.newBuilder();
				resultBuilder.setStatus(ResponseProto.Response.Status.OK);
				resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
				ctx.writeAndFlush(resultBuilder.build());
				break;
			default:
				System.out.println("Don't know this type");
		}
 	}
	
	private Object error() {
		ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
		
		ResponseProto.RespFailed.Builder failedBuilder = ResponseProto.RespFailed.newBuilder();
		failedBuilder.setCode(SystemErrorCodes.UNLOGIN.getCode());
		failedBuilder.setError(SystemErrorCodes.UNLOGIN.getError());
		failedBuilder.setErrorDescription("用户无法登陆");
		ResponseProto.RespFailed respFailed = failedBuilder.build();
		
		resultBuilder.setStatus(ResponseProto.Response.Status.ERROR);
		resultBuilder.setExtension(ResponseProto.RespFailed.respfailed, respFailed);
		return resultBuilder.build();
	}
	
	private Object resp(LoginReqProto.LoginReq loginReq, ChannelHandlerContext ctx) {
		ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();
		// 验证用户名、密码
		UsernamePasswordToken token = new UsernamePasswordToken(loginReq.getUsername(), loginReq.getPassword());
		Subject subject = SecurityUtils.getSubject();
		try {
			subject.login(token);
			
			LoginRespProto.LoginResp.Builder loginBuilder = LoginRespProto.LoginResp.newBuilder();
			loginBuilder.setResult("登录成功");
			
			User user = (User) subject.getSession().getAttribute("user");
			
			ServerManager.addOnlineContext(user.getId(), ctx);
			
			UserInfoProto.UserInfo.Builder userInfoBuilder = UserInfoProto.UserInfo.newBuilder();
			if (user.getBirthday() != null)
				userInfoBuilder.setBirthday(DateUtils.format(user.getBirthday(), DateUtils.FORMAT_SHORT));
			if (user.getHeight() != null)
				userInfoBuilder.setHeight(user.getHeight());
			if (user.getWeight() != null)
				userInfoBuilder.setWeight(user.getWeight());
			userInfoBuilder.setLocked(user.getLocked());
			if (user.getMedicalHistory() != null)
				userInfoBuilder.setMedicalHistory(user.getMedicalHistory());
			if (user.getMobile() != null)
				userInfoBuilder.setMobile(user.getMobile());
			if (user.getPosition() != null)
				userInfoBuilder.setPosition(user.getPosition());
			if (user.getRealName() != null)
				userInfoBuilder.setRealName(user.getRealName());
			if (user.getSex() != null)
				userInfoBuilder.setSex(user.getSex());
			userInfoBuilder.setUsername(user.getUsername());
			if (user.getWorkingPlace() != null)
				userInfoBuilder.setWorkingPlace(user.getWorkingPlace());
			
			loginBuilder.setUserInfo(userInfoBuilder.build());
			
			ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
			respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.LOGIN);
			respSuccessBuilder.setExtension(LoginRespProto.LoginResp.loginResp, loginBuilder.build());
			
			resultBuilder.setStatus(ResponseProto.Response.Status.OK);
			resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
			
		} catch (AuthenticationException e) {
			logger.info("登录失败" + e.getMessage());
			ResponseProto.RespFailed.Builder failedBuilder = ResponseProto.RespFailed.newBuilder();
			failedBuilder.setCode(SystemErrorCodes.UNLOGIN.getCode());
			failedBuilder.setError(SystemErrorCodes.UNLOGIN.getError());
			failedBuilder.setErrorDescription("用户无法登陆");
			ResponseProto.RespFailed respFailed = failedBuilder.build();
			
			resultBuilder.setStatus(ResponseProto.Response.Status.ERROR);
			resultBuilder.setExtension(ResponseProto.RespFailed.respfailed, respFailed);
		}
		return resultBuilder.build();
	}
	
	public Object getResourceList(String resourceId) {
		Subject subject = SecurityUtils.getSubject();
		ResourceListRespProto.ResourceListResp.Builder resourceListBuilder = 
				ResourceListRespProto.ResourceListResp.newBuilder();
		// 一级栏目列表/权限
//		List<Resource> resources = resourceService.loadFirsts();
		List<ResourceDto> resources = resourceService.findAll();
		
		// 用户信息
		for (ResourceDto resource : resources) {
			ResourceProto.Resource.Builder resourceBuilder = ResourceProto.Resource.newBuilder();
			resourceBuilder.setName(resource.getName());
			resourceBuilder.setId(resource.getId());
			resourceBuilder.setSeq(resource.getSeq());
			resourceBuilder.setParentIds(resource.getParentIds());
			if (subject.isPermitted(resource.getPermission().getCode())) {
				resourceBuilder.setIsEnabled(true);
			} else {
				resourceBuilder.setIsEnabled(false);
			}
			resourceListBuilder.addResource(resourceBuilder.build());
		}
		resourceListBuilder.setResult("获取资源列表成功");
		ResponseProto.Response.Builder resultBuilder = ResponseProto.Response.newBuilder();

		ResponseProto.RespSuccess.Builder respSuccessBuilder = ResponseProto.RespSuccess.newBuilder();
		respSuccessBuilder.setType(ResponseProto.RespSuccess.Type.RESOURCE_LIST);
		respSuccessBuilder.setExtension(ResourceListRespProto.ResourceListResp.resourceListResp, resourceListBuilder.build());
		
		resultBuilder.setStatus(ResponseProto.Response.Status.OK);
		resultBuilder.setExtension(ResponseProto.RespSuccess.respSuccess, respSuccessBuilder.build());
		return resultBuilder.build();
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
	
	@Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		Subject subject = SecurityUtils.getSubject();
//		User user = (User) subject.getSession().getAttribute("user");
		ServerManager.ungisterUserContext(ctx);
		subject.logout();
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "掉线");
        ctx.fireChannelInactive();
    }

}
